using System;
using System.Collections.Generic;

namespace Client.Hotfix
{
    public class MessageMap<T, M> where T : notnull
    {
        private Dictionary<T, Action<M>> listeners = new();
        private Dictionary<object, List<T>> targetListeners = new();

        public void Destroy()
        {
            listeners?.Clear();
            targetListeners?.Clear();
            listeners = null;
            targetListeners = null;
        }

        public void AddListener(T cmd, Action<M> handler)
        {
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }

            if (listeners.ContainsKey(cmd))
            {
                this.LogYellow($"this cmd is already added : {cmd} ! ");
            }

            listeners[cmd] = handler;

            if (handler.Target != null)
            {
                if (!targetListeners.ContainsKey(handler.Target))
                {
                    targetListeners.Add(handler.Target, new List<T>());
                }

                List<T> eventList = targetListeners[handler.Target];
                if (!eventList.Contains(cmd))
                {
                    eventList.Add(cmd);
                }
            }
        }

        public void RemoveListenerByKey(T cmd)
        {
            if (listeners.ContainsKey(cmd))
            {
                var handler = listeners[cmd];
                if (handler != null && handler.Target != null && targetListeners.ContainsKey(handler.Target))
                {
                    var keyList = targetListeners[handler.Target];
                    keyList.Remove(cmd);

                    if (keyList.Count == 0)
                    {
                        targetListeners.Remove(handler.Target);
                    }
                }
                listeners.Remove(cmd);
            }
        }

        public void RemoveListenerByClass(object target)
        {
            if (targetListeners.ContainsKey(target))
            {
                var keyList = targetListeners[target];
                for (int i = keyList.Count - 1; i >= 0; i--)
                {
                    T key = keyList[i];
                    if (listeners.ContainsKey(key))
                    {
                        var handler = listeners[key];
                        if (handler != null && handler.Target == target)
                        {
                            listeners.Remove(key);
                        }
                    }
                }
                targetListeners.Remove(target);
            }
        }
        public void Invoke(T cmd, M message)
        {
            if (listeners.TryGetValue(cmd, out var handler))
            {
                handler?.Invoke(message);
            }
        }
    }
}